package ldap

import (
	"context"
	"fmt"

	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/code"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/domain"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/token"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/token/provider"
	"gitee.com/go-course/go8/projects/devcloud/mcenter/apps/user"
	"github.com/infraboard/mcube/app"
	"github.com/infraboard/mcube/exception"
	"github.com/infraboard/mcube/logger"
	"github.com/infraboard/mcube/logger/zap"
)

type issuer struct {
	user user.Service

	log logger.Logger
}

func (i *issuer) Init() error {
	i.user = app.GetInternalApp(user.AppName).(user.Service)
	i.log = zap.L().Named("issuer.ldap")
	return nil
}

func (i *issuer) GrantType() token.GRANT_TYPE {
	return token.GRANT_TYPE_LDAP
}

func (i *issuer) IssueToken(ctx context.Context, req *token.IssueTokenRequest) (
	*token.Token, error) {
	if req.GrantType != token.GRANT_TYPE_LDAP {
		return nil, fmt.Errorf("ldap 颁发器，只支持GrantType LDAP")
	}

	// 可以保持在配置文件中
	conf := domain.NewDefaultLDAPConfig()
	conf.Url = "ldap://127.0.0.1:389"
	conf.BindDn = "cn=admin,dc=example,dc=org"
	conf.BindPassword = "admin"
	conf.BaseDn = "dc=example,dc=org"
	conf.UserFilter = "(uid={input})"

	// 怎么验证用户传递的LDAP 用户和密码是否正确
	p := NewProvider(conf)
	err := p.CheckConnect()
	if err != nil {
		return nil, err
	}

	u, err := p.CheckUserPassword(req.Username, req.Password)
	if err != nil {
		return nil, err
	}
	// 认证通过, 确认用户是否存在
	descReq := user.NewDescriptUserRequestWithName(req.Username)
	lu, err := i.user.DescribeUser(ctx, descReq)
	if err != nil {
		if exception.IsNotFoundError(err) {
			// 进行用户的创建
			createReq := user.NewCreateUserRequest()
			createReq.Username = req.Username
			createReq.Password = req.Password
			createReq.Type = user.TYPE_SUB
			_, err := i.user.CreateUser(ctx, createReq)
			if err != nil {
				return nil, err
			}
		}
		return nil, err
	}

	// 如果用户在本地数据库存在, 需要更新信息
	fmt.Println(u)

	// LDAP认证检查通过, 颁发Token
	// 颁发Token
	tk := token.NewToken(req)
	tk.Domain = lu.Spec.Domain
	tk.Username = lu.Spec.Username
	tk.UserType = lu.Spec.Type
	tk.UserId = lu.Id

	return tk, nil
}

func (i *issuer) IssueCode(context.Context, *code.IssueCodeRequest) (*code.Code, error) {
	return nil, fmt.Errorf("not impl")
}

func init() {
	provider.Registe(&issuer{})
}
